#-----------------------------------------------------------------
# frontend.c: IRNode
# ast node classes.
#
# Original copyright (c) 2008, eli bendersky
# Current version from Ruyman Reyes, 2010
# license: lgpl
#-----------------------------------------------------------------

import sys
import copy as Copy





class IRNode(object):
    """ Abstract base class for AST nodes.
    """
    def children(self):
        """ A sequence of all children that are Nodes
        """
        pass

    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
        """ Pretty print the Node and all its attributes and
            children (recursively) to a buffer.
            
            file:   
                Open IO buffer into which the Node is printed.
            
            offset: 
                Initial offset (amount of leading spaces) 
            
            attrnames:
                True if you want to see the attribute names in
                name=value pairs. False to only see the values.
            
            showcoord:
                Do you want the coordinates of each Node to be
                displayed.
        """
        pass

    # Avoid recursive copying
    __nocopy__ = ['parent',]

    def __copy__(self):
        # new = self.__class__(*self.__dict__)
        new = self.__class__(**self._initial_entries)
        new.__dict__.update(self.__dict__)
        return new

    def __init__(self, dict):
        self.__dict__ = dict
        self._rootNodeClass = None

    def __simplecopy__(self, value):
        rvalue = None
        if type(value) == type([]):
#            print " List "
            tmp = []
            for elem in value:
                if hasattr(elem, '__deepcopy__'):
                    tmp.append(elem.__deepcopy__())
                elif hasattr(elem, '__copy__'):
                    tmp.append(elem.__copy__())
                else:
                    tmp.append(elem)

            rvalue = tmp
        elif type(value) == type(""):
#            print " String "
            rvalue = value[:]
        elif type(value) == type(1) or type(value) == type(1.0):
 #           print " Scalar "
            rvalue = value
        elif type(value) == type({}):
#            print " Dictionary : " + str(value)
            newdict = dict().fromkeys(value)
            for k,v in newdict.iteritems():
                newdict[k] = self.__simplecopy__(v)
            rvalue = newdict
        else:
 #           print " Who nows ... " + str(type(value))
            if type(value) == type(None):
                rvalue = None
            else:
                rvalue = Copy.deepcopy(value)
        return rvalue

    def __deepcopy__(self, memo = {}):
        new = self.__class__(*self._initial_entries)
        partial_dict = {}
        for key,value in self.__dict__.items():
            if key not in self.__nocopy__ and not value in memo.keys():
                partial_dict[key] = self.__simplecopy__(value)
            else:
#                print " This value does not need to be copied \n"
                partial_dict[key] = value
        new.__dict__.update(partial_dict)
        # Disable parents at deepcopy, need to relink subtree
        new.parent = None
        return new
    def getRootNode(self):
        """ Returns the FileAST Ancestor of the given node.
            Raise NodeNotFound if not found
            
                :return: RootNode containing the node 
        """
        tmp = self
        while tmp.parent != None:
            tmp = tmp.parent

        return tmp

#        while type(tmp) != self._rootNodeClass:
#            if hasattr(tmp, 'parent'):
#                tmp = tmp.parent
#            else:
#                raise NotValidParent(self)
#        return tmp    
    
    
    def getContainerAttribute(self):
            """ Returns the attribute containing the node
            
                :param node: Node to search
                :return: String with the name of the attribute
            """
            if not node.parent:
                raise NotValidParent(node)
            parent = self.parent
            # print " Looking for: " + str(node) + " In: " + str(parent)
            for attr in parent.__dict__:
                if type(parent.__dict__[attr]) == type([]):
                    for elem in parent.__dict__[attr]:
                        if elem == node:
                            return attr
                elif parent.__dict__[attr] == self:
                        return attr
                else:    
                    pass
            raise NotValidParent(self)
    
   


class IRNodeVisitor(object):
    """ A base NodeVisitor class for visiting c_ast nodes. 
        Subclass it and define your own visit_XXX methods, where
        XXX is the class name you want to visit with these 
        methods.
        
        For example:
        
        class ConstantVisitor(NodeVisitor):
            def __init__(self):
                self.values = []
            
            def visit_Constant(self, node):
                self.values.append(node.value)

        Creates a list of values of all the constant nodes 
        encountered below the given node. To use it:
        
        cv = ConstantVisitor()
        cv.visit(node)
        
        Notes:
        
        *   generic_visit() will be called for AST nodes for which 
            no visit_XXX method was defined. 
        *   The children of nodes for which a visit_XXX was 
            defined will not be visited - if you need this, call
            generic_visit() on the node. 
            You can use:
                NodeVisitor.generic_visit(self, node)
        *   Modeled after Python's own AST visiting facilities
            (the ast module of Python 3.0)
    """
    def visit(self, node):
        """ Visit a node. 
        """
        method = 'visit_' + node.__class__.__name__
        visitor = getattr(self, method, self.generic_visit)
        return visitor(node)
        
    def generic_visit(self, node):
        """ Called if no explicit visitor function exists for a 
            node. Implements preorder visiting of the node.
        """
        for c in node.children():
            self.visit(c)


